package com.colorsstudio.defence.baseClass
{
	import com.colorsstudio.defence.algorithm.AStarLine;
	import com.colorsstudio.defence.algorithm.Waypoint;
	import com.colorsstudio.defence.baseClass.Enemy;
	import com.colorsstudio.defence.ConstantValues.Constants;
	import com.colorsstudio.defence.Levels.gameScene1;
	import com.colorsstudio.defence.util.singletonFactory1;
	import com.colorsstudio.defence.util.Vector2D;
	import com.greensock.*;
	import com.greensock.easing.*;
	import de.polygonal.ds.Array2;
	import de.polygonal.ds.ArrayedQueue;
	import de.polygonal.ds.Graph;
	import de.polygonal.ds.GraphNode;
	import flash.display.MovieClip;
	import flash.display.SimpleButton;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.events.TimerEvent;
	import flash.utils.Timer;
	import idv.cjcat.signals.ISignal;
	import idv.cjcat.signals.Signal;
	import com.greensock.plugins.*;
	
	TweenPlugin.activate([DynamicPropsPlugin]);
	
	/**
	 * ...
	 * @author wuzhida
	 */
	public class Tower extends MovieClip
	{
		public var gridW:int;
		public var gridH:int;
		public var signalTowerPlace:ISignal = new Signal(int, int);
		public var signalEnemyKill:ISignal = new Signal();
		public var attackSpeed:int = 1000;
		public var enemyArray:Array = new Array();
		public var towerArray:Array = new Array();
		public var attackTimer:Timer = new Timer(1000, 1);
		public var currentEnemy:Enemy;
		public var lastEnemy:Enemy;
		//设置攻击长度
		public var radius:Number;
		public const DISTANSE:Number = 160;
		public var power:int = 3;
		public var bullet:MovieClip;
		public var graph:Graph
		public var pathExists:Boolean;
		public var startNode:GraphNode;
		public var endNode:GraphNode;
		public var startNodeIndex:int;
		public var endNodeIndex:int;
		//记录是否当前格子有物体
		public var mapStatus:Array2;
		//记录删除的边
		public var arcArray:ArrayedQueue = new ArrayedQueue(200);
		public var placeFlag:Boolean;
		//定时器，用于检测当前的放置是否合理
		public var placeTimer:Timer = new Timer(200);
		public var btnSeld:SimpleButton;
		public var btnUpGrade:SimpleButton;
		//添加flag值来判断打开和关闭
		public var buttonOpen:Boolean;
		public var towerRingGreen:Sprite;
		public var towerRingRed:Sprite;
		public var container:Sprite;
		
		//因为是一共72帧，所以是5°为一帧
		public var movieClipIndex:int = 1;
		public var enemyVector2d:Vector2D;
		public var towerVector2d:Vector2D;
		public var currentRotation:Number;
		
		//更新player 信息		
		public var player:Player = singletonFactory1(Player);
		
		//需要一个flag来记录当前是否在攻击敌人，如果攻击敌人，则让枪头进行平衡旋转。
		public var isAttacking:Boolean = false;
		//需要一个flag来记录是否需要转换攻击的敌人，例如，当进入视野时，才进行攻击，这时候设置为true
		//当攻击出了视野之外后，才设置为false，这时候才重新设置currentEnemy。
		//一开始当然需要设置true，因为此时为null，需要新的currentEnemy
		public var isEnemyChange:Boolean = true;
		
		public function Tower(x:Number, y:Number)
		{
			//因为我要用到他的parent.parent,也就是获得数组，所以需要在gamescene1把它new出来之后并addCHild之后才可以调用
			this.addEventListener(Event.ADDED, init, false, 0, true);
		}
		
		private function init(e:Event):void
		{
			attackSpeed = 1000 / Constants.TIME_SCALE;
			this.gotoAndStop(movieClipIndex);
			this.removeEventListener(Event.ADDED, init, false);
			//首先把父类的enemyArray and graph拿下来
			enemyArray = gameScene1(this.parent.parent).enemyArray;
			towerArray = gameScene1(this.parent.parent).arrayTower;
			graph = gameScene1(this.parent.parent).graph;
			mapStatus = gameScene1(this.parent.parent).mapStatus;
			//计算当前的格子
			gridW = x / Constants.DEFENCER_WIDTH - 1;
			gridH = y / Constants.DEFENCER_HEIGHT - 1;
			//把它设置在格子中心
			this.x = (gridW + 1) * Constants.DEFENCER_WIDTH;
			this.y = (gridH + 1) * Constants.DEFENCER_HEIGHT;
			//监听每帧，然后移动，当再点击鼠标的时候就放置塔
			this.addEventListener(Event.ENTER_FRAME, moveWithMouse, false, 0, true);
			this.addEventListener(Event.ENTER_FRAME, moveGunRotation, false, 0, true);
			this.addEventListener(MouseEvent.CLICK, placeTower, false, 0, true);
			placeTimer.addEventListener(TimerEvent.TIMER, placeCheck, false, 0, true);
			placeTimer.start();
			radius = DISTANSE * 1.41;
			//设置子弹
			bullet = new f_bullet();
			this.parent.addChild(bullet);
			bullet.visible = false;
			bullet.mouseEnabled = false;
			this.buttonMode = true;
			//设置绿环和红环
			container = new Sprite();
			this.parent.addChild(container);
			towerRingGreen = new f_towerRingGreen();
			towerRingRed = new f_towerRingRed();
			towerRingGreen.width = radius;
			towerRingGreen.height = radius;
			towerRingRed.height = radius;
			towerRingRed.width = radius;
			container.mouseEnabled = false;
			towerRingRed.mouseEnabled = false;
			towerRingGreen.mouseEnabled = false;
			container.addChild(towerRingGreen);
			container.addChild(towerRingRed);
			towerRingRed.visible = false;
			towerRingGreen.visible = true;
		
		}
		
		private function moveGunRotation(e:Event):void
		{
			if (isAttacking && currentEnemy != null)
			{
				currentRotation = 360 * (Math.atan2(currentEnemy.y - this.y, currentEnemy.x - this.x) / (2 * Math.PI)) + 180;
				movieClipIndex = currentRotation / 5;
				this.gotoAndStop(movieClipIndex);
			}
		}
		
		private function placeCheck(e:TimerEvent):void
		{
			placeFlag = true;
			//0、如果把塔放在允许的范围之外
			if (gridW < 0 || gridW > 15 || gridH < 0 || gridH > 8)
			{
				placeFlag = false;
				
			}
			//1、如果与敌人相碰
			//这个还有个更好的解决方法，就是当有敌人在塔下面的时候，就不要去计算图的变化，让他继续按照原来那样走。
			/*for each (var item:Enemy in enemyArray)
			   {
			   if (item.hitTestObject(hitTestSprite))
			   {
			   placeFlag = false;
			   //这里和下面都不可以直接return，因为在这个函数的最后，还需要gotoandstop2
			   break;
			   }
			 }*/
			//2、如果与塔相碰
			if (placeFlag == true)
			{
				var isSet:Boolean = mapStatus.get(gridW, gridH);
				if (isSet)
				{
					//这里和下面都不可以直接return，因为在这个函数的最后，还需要gotoandstop2
					placeFlag = false;
					
				}
			}
			//3、如果没有路径
			if (placeFlag == true)
			{
				startNodeIndex = 4 * 16 + 0;
				endNodeIndex = 2 * 16 + 15;
				startNode = graph.nodes[startNodeIndex];
				endNode = graph.nodes[endNodeIndex];
				//graph.removeNode(gridW + gridH * 16);
				{
					var l:int = gridW;
					var k:int = gridH;
					if (l > 0)
					{
						graph.removeArc(l + k * 16, l - 1 + k * 16);
						graph.removeArc(l - 1 + k * 16, l + k * 16);
					}
					if (l < 15)
					{
						graph.removeArc(l + k * 16, l + 1 + k * 16);
						graph.removeArc(l + 1 + k * 16, l + k * 16);
					}
					if (k > 0)
					{
						graph.removeArc(l + k * 16, l + (k - 1) * 16);
						graph.removeArc(l + (k - 1) * 16, l + k * 16);
					}
					if (k < 8)
					{
						graph.removeArc(l + k * 16, l + (k + 1) * 16);
						graph.removeArc(l + (k + 1) * 16, l + k * 16);
					}
				}
				
				pathExists = AStarLine.find(graph, startNode, endNode);
				
				////////trace("A HA, the path is not exists!");
				//重新添加node
				//graph.addNode(new Waypoint(l + k * 16), l + k * 16);
				if (!pathExists)
				{
					placeFlag = false;
					
				}
				if (l > 0 && mapStatus.get(gridW - 1, gridH) == 0)
				{
					////trace("add");
					graph.addArc(l + k * 16, l - 1 + k * 16);
					graph.addArc(l - 1 + k * 16, l + k * 16);
				}
				if (l < 15 && mapStatus.get(gridW + 1, gridH) == 0)
				{
					////trace("add");
					graph.addArc(l + k * 16, l + 1 + k * 16);
					graph.addArc(l + 1 + k * 16, l + k * 16);
				}
				if (k > 0 && mapStatus.get(gridW, gridH - 1) == 0)
				{
					////trace("add");
					graph.addArc(l + k * 16, l + (k - 1) * 16);
					graph.addArc(l + (k - 1) * 16, l + k * 16);
				}
				if (k < 8 && mapStatus.get(gridW, gridH + 1) == 0)
				{
					////trace("add");
					graph.addArc(l + k * 16, l + (k + 1) * 16);
					graph.addArc(l + (k + 1) * 16, l + k * 16);
				}
				
				gameScene1(this.parent.parent).draw();
			}
			
			if (placeFlag == false)
			{
				towerRingRed.visible = true;
				towerRingGreen.visible = false;
			}
			else
			{
				towerRingRed.visible = false;
				towerRingGreen.visible = true;
			}
		}
		
		public function placeTower(e:MouseEvent):void
		{
			gridW = x / Constants.DEFENCER_WIDTH - 1;
			gridH = y / Constants.DEFENCER_HEIGHT - 1;
			//超出的时候就把它removeChild了，记得还要把gameScene1里面的数组里面的那个引用给清除掉，
			//要不然还会有这个的引用。然后actionscript没有他的引用，自动就会回收
			//记得this首先是addChild到layer2上，所以this的parent是layer2		
			//如果放在外面，则把自己删除
			if (gridW < 0 || gridW > 15 || gridH < 0 || gridH > 8)
			{
				var index:int = (this.parent.parent as gameScene1).arrayTower.indexOf(this);
				(this.parent.parent as gameScene1).arrayTower.splice(index, 1);
				this.removeEventListener(Event.ENTER_FRAME, moveWithMouse, false);
				this.removeEventListener(MouseEvent.CLICK, placeTower, false);
				
				container.removeChild(towerRingGreen);
				container.removeChild(towerRingRed);
				this.parent.removeChild(container);
				this.parent.removeChild(this);
			}
			else
			{
				if (placeFlag == true)
				{
					var l:int = gridW;
					var k:int = gridH;
					if (l > 0)
					{
						graph.removeArc(l + k * 16, l - 1 + k * 16);
						graph.removeArc(l - 1 + k * 16, l + k * 16);
					}
					if (l < 15)
					{
						graph.removeArc(l + k * 16, l + 1 + k * 16);
						graph.removeArc(l + 1 + k * 16, l + k * 16);
					}
					if (k > 0)
					{
						graph.removeArc(l + k * 16, l + (k - 1) * 16);
						graph.removeArc(l + (k - 1) * 16, l + k * 16);
					}
					if (k < 8)
					{
						graph.removeArc(l + k * 16, l + (k + 1) * 16);
						graph.removeArc(l + (k + 1) * 16, l + k * 16);
					}
					
					//this.gotoAndStop(1);
					this.removeEventListener(Event.ENTER_FRAME, moveWithMouse, false);
					this.removeEventListener(MouseEvent.CLICK, placeTower, false);
					this.x = (gridW + 1) * Constants.DEFENCER_WIDTH;
					this.y = (gridH + 1) * Constants.DEFENCER_HEIGHT;
					mapStatus.set(gridW, gridH, 1);
					//需要重新计算地图：
					signalTowerPlace.dispatch(gridW, gridH);
					attack();
					gameScene1(this.parent.parent).draw();
					placeTimer.removeEventListener(TimerEvent.TIMER, placeCheck, false);
					placeTimer.stop();
					this.addEventListener(MouseEvent.CLICK, seldOrUpGrade, false, 0, true);
					towerRingRed.visible = false;
					towerRingGreen.visible = false;
				}
			}
		}
		
		private function seldOrUpGrade(e:MouseEvent):void
		{
			//trace(e.currentTarget);
			//trace(e.target);
			if (e.target as f_btnSeld)
			{
				return;
			}
			this.parent.addChildAt(this, this.parent.numChildren - 1);
			if (btnSeld == null)
			{
				btnSeld = new f_btnSeld();
				btnSeld.x = 24;
				btnSeld.y = 24;
				this.addChild(btnSeld);
			}
			if (btnUpGrade == null)
			{
				btnUpGrade = new f_btnUpGrade();
				btnUpGrade.x = 24;
				btnUpGrade.y = 24;
				this.addChild(btnUpGrade);
			}
			if (buttonOpen == false)
			{
				btnUpGrade.scaleX = btnUpGrade.scaleY = 0;
				btnSeld.scaleX = btnSeld.scaleY = 0;
				TweenLite.to(btnSeld, 1, {x: 24 - (Constants.DEFENCER_WIDTH / 2 + 14.5), y: 24, scaleX: 1, scaleY: 1, ease: Elastic.easeOut});
				TweenLite.to(btnUpGrade, 1, {x: 24 + (Constants.DEFENCER_WIDTH / 2 + 14.5), y: 24, scaleX: 1, scaleY: 1, ease: Elastic.easeOut});
				buttonOpen = true;
				//当前是打开的状态，可以添加按钮的监听事件
				btnSeld.addEventListener(MouseEvent.CLICK, btnSeldEvent, false, 0, true);
				btnUpGrade.addEventListener(MouseEvent.CLICK, btnUpGradeEvent, false, 0, true);
			}
			else
			{
				TweenLite.to(btnSeld, 1, {x: 24, y: 24, scaleX: 0, scaleY: 0, ease: Elastic.easeOut});
				TweenLite.to(btnUpGrade, 1, {x: 24, y: 24, scaleX: 0, scaleY: 0, ease: Elastic.easeOut});
				buttonOpen = false;
				//当前是关闭的状态，可以移除按钮的监听事件
				btnSeld.removeEventListener(MouseEvent.CLICK, btnSeldEvent, false);
				btnUpGrade.removeEventListener(MouseEvent.CLICK, btnUpGradeEvent, false);
			}
		}
		
		private function btnUpGradeEvent(e:MouseEvent):void
		{
			this.scaleX = 1.2;
			this.scaleY = 1.2;
		}
		
		private function btnSeldEvent(e:MouseEvent):void
		{
			//trace("Hello , i click the left button!", gridW, "   ", gridH);
			var l:int = gridW;
			var k:int = gridH;
			
			if (l > 0)
			{
				graph.addArc(l + k * 16, l - 1 + k * 16, 1);
				graph.addArc(l - 1 + k * 16, l + k * 16, 1);
			}
			if (l < 15)
			{
				graph.addArc(l + k * 16, l + 1 + k * 16, 1);
				graph.addArc(l + 1 + k * 16, l + k * 16, 1);
			}
			if (k > 0)
			{
				graph.addArc(l + k * 16, l + (k - 1) * 16, 1);
				graph.addArc(l + (k - 1) * 16, l + k * 16, 1);
			}
			if (k < 8)
			{
				graph.addArc(l + k * 16, l + (k + 1) * 16, 1);
				graph.addArc(l + (k + 1) * 16, l + k * 16, 1);
			}
			mapStatus.set(gridW, gridH, 0);
			towerArray.splice(towerArray.indexOf(this), 1);
			signalTowerPlace.dispatch(gridW, gridH);
			dispose();
		}
		
		public function dispose():void
		{
			attackTimer.stop();
			placeTimer.stop();
			this.removeEventListener(Event.ENTER_FRAME, moveWithMouse, false);
			this.removeEventListener(MouseEvent.CLICK, placeTower, false);
			placeTimer.removeEventListener(TimerEvent.TIMER, placeCheck, false);
			btnSeld.removeEventListener(MouseEvent.CLICK, btnSeldEvent, false);
			btnUpGrade.removeEventListener(MouseEvent.CLICK, btnUpGradeEvent, false);
			
			container.removeChild(towerRingGreen);
			container.removeChild(towerRingRed);
			this.parent.removeChild(container);
			
			this.removeChild(btnSeld);
			this.removeChild(btnUpGrade);
			this.parent.removeChild(this);
		}
		
		public function moveWithMouse(e:Event):void
		{
			//这里要用stage的mouseX，要不然就是相对this的mouseX，一直没发现
			//this.x = this.stage.mouseX;
			//this.y = this.stage.mouseY;
			//计算当前的格子
			gridW = this.stage.mouseX / Constants.DEFENCER_WIDTH - 1;
			gridH = this.stage.mouseY / Constants.DEFENCER_HEIGHT - 1;
			//把它设置在格子中心
			this.x = (gridW + 1) * Constants.DEFENCER_WIDTH;
			this.y = (gridH + 1) * Constants.DEFENCER_HEIGHT;
			
			container.x = this.x + this.width / 2;
			container.y = this.y + this.height / 2;
			//////trace(mouseX, "   " , mouseY);
		
		}
		
		//塔可以开始攻击，当然也可以停止攻击
		public function attack():void
		{
			attackTimer = new Timer(attackSpeed);
			attackTimer.addEventListener(TimerEvent.TIMER, searchNearestEnemy, false, 0, true);
			attackTimer.start();
		}
		
		public function stopAttack():void
		{
			attackTimer.stop();
			attackTimer.removeEventListener(TimerEvent.TIMER, searchNearestEnemy, false);
			attackTimer = null;
		}
		
		public function pauseAttack():void
		{
			attackTimer.stop();
		}
		
		private function searchNearestEnemy(e:TimerEvent):void
		{
			//排序
			if (enemyArray.length == 0)
				return;
			if (isEnemyChange)
			{
				enemyArray.sort(sortOnDistance);
				currentEnemy = enemyArray[0];
				isEnemyChange = false;
			}
			if (currentEnemy == null)
				return;
			//如果超出范围，donotthing			
			if (Math.sqrt((currentEnemy.x - this.x) * (currentEnemy.x - this.x) + (currentEnemy.y - this.y) * (currentEnemy.y - this.y)) > radius)
			{
				var t:Enemy;
				enemyArray.sort(sortOnDistance);
				t = enemyArray[0];
				currentRotation = 360 * (Math.atan2(t.y - this.y, t.x - this.x) / (2 * Math.PI)) + 180;
				movieClipIndex = currentRotation / 5;
				this.gotoAndStop(movieClipIndex);
				
				isAttacking = false;
				isEnemyChange = true;
				return;
			}
			else if (currentEnemy.currentHealth > 0)
			{
				//变色
				//变色
				//currentEnemy.gotoAndStop(2);
				//发射子弹
				isAttacking = true;
				/*enemyVector2d = new Vector2D(currentEnemy.x, currentEnemy.y);
				 towerVector2d = new Vector2D(this.x, this.y);*/
				
				//trace(currentRotation);
				bullet.visible = true;
				bullet.x = this.x + 24;
				bullet.y = this.y + 24;
				//TweenLite.to(bullet, .8, { x:currentEnemy.x, y:currentEnemy.y, ease:Linear.easeNone, onComplete:removeBullet } );
				TweenMax.to(bullet, .4, {dynamicProps: {x: getEnemyX, y: getEnemyY}, ease: Linear.easeNone, onComplete: removeBullet});
				
				//变色，改变攻击目标
				if (lastEnemy == null)
				{
					lastEnemy = currentEnemy;
				}
				else if (currentEnemy != lastEnemy)
				{
					//////trace("Now attacking another enemy!");
					//lastEnemy.gotoAndStop(1);					
					lastEnemy = currentEnemy;
				}
				
			}
		}
		
		private function removeBullet():void
		{
			////trace("removeBullet");
			bullet.visible = false;
			if (currentEnemy.currentHealth <= 0)
				return;
			currentEnemy.currentHealth -= this.power;
			if (currentEnemy.currentHealth < 0)
			{
				currentEnemy.currentHealth = 0;
			}
			currentEnemy.lifeSprite.width = currentEnemy.currentHealth / currentEnemy.health * currentEnemy.lifeWidth;
			
			if (currentEnemy.currentHealth <= 0)
			{
				//加分，更新数字
				trace("ADDSCORE");
				player.currentScore += currentEnemy.earnScore;
				player.currentMoney++;
				signalEnemyKill.dispatch();
				
				enemyArray.splice(enemyArray.indexOf(currentEnemy), 1);
				if (currentEnemy.parent != null)
				{
					currentEnemy.parent.removeChild(currentEnemy);
					isEnemyChange = true;
				}
				currentEnemy = null;
				
			}
		}
		
		private function getEnemyX():Number
		{
			var lastX:Number;
			if (currentEnemy != null)
			{
				lastX = currentEnemy.x;
				return currentEnemy.x;
			}
			else
			{
				return lastX;
			}
		}
		
		private function getEnemyY():Number
		{
			var lastY:Number;
			if (currentEnemy != null)
			{
				lastY = currentEnemy.y;
				return currentEnemy.y;
			}
			else
			{
				return lastY
			}
		}
		
		private function sortOnDistance(e1:Enemy, e2:Enemy)
		{
			var d1:Number = (e1.x - this.x) * (e1.x - this.x) + (e1.y - this.y) * (e1.y - this.y);
			var d2:Number = (e2.x - this.x) * (e2.x - this.x) + (e2.y - this.y) * (e2.y - this.y);
			if (d1 < d2)
			{
				return -1;
			}
			else if (d1 > d2)
			{
				return 1;
			}
			else
			{
				return 0;
			}
		}
		
		public function pause():void
		{
			placeTimer.stop();
			attackTimer.stop();
		}
		
		public function unPause():void
		{
			placeTimer.start();
			attackTimer.start();
		}
		
		public function speedUp(num:Number):void
		{
			trace("speedUpTTT");
			attackTimer.stop();
			attackTimer.removeEventListener(TimerEvent.TIMER, searchNearestEnemy, false);
			attackSpeed = 1000 / num;
			attackTimer = new Timer(attackSpeed as int);
			attackTimer.addEventListener(TimerEvent.TIMER, searchNearestEnemy, false, 0, true);
			attackTimer.start();
		}
	}
}